/*
 * BigInteger.cpp
 *
 *  Created on: 07.04.2014
 *      Author: nicolas.winkler
 */

#include "BigInteger.h"
#include <sstream>
#include <iostream>
#include <cmath>

using namespace math;


BigInteger::BigInteger(void)
{
	this->value = 0;
}


BigInteger::BigInteger(const BigInteger& value)
{
	this->value = value.value;
}


BigInteger::BigInteger(long long value)
{
	this->value = value;
}


BigInteger::~BigInteger(void)
{
}


const BigInteger& BigInteger::operator = (const BigInteger& value)
{
	this->value = value.value;
	return *this;
}


const BigInteger& BigInteger::operator += (const BigInteger& summand)
{
	this->value += summand.value;
	return *this;
}


const BigInteger& BigInteger::operator -= (const BigInteger& subtrahend)
{
	this->value -= subtrahend.value;
	return *this;
}


const BigInteger& BigInteger::operator *= (const BigInteger& factor)
{
	this->value *= factor.value;
	return *this;
}


const BigInteger& BigInteger::operator /= (const BigInteger& divisor)
{
	this->value /= divisor.value;
	return *this;
}


const BigInteger& BigInteger::operator %= (const BigInteger& divisor)
{
	this->value %= divisor.value;
	return *this;
}


const BigInteger BigInteger::operator + (const BigInteger& summand) const
{
	BigInteger sum;
	sum.value = this->value + summand.value;
	return sum;
}


const BigInteger BigInteger::operator - (const BigInteger& subtrahend) const
{
	BigInteger difference;
	difference.value = this->value - subtrahend.value;
	return difference;
}


const BigInteger BigInteger::operator * (const BigInteger& factor) const
{
	BigInteger product;
	product.value = this->value * factor.value;
	return product;
}


const BigInteger BigInteger::operator / (const BigInteger& divisor) const
{
	BigInteger quotient;
	quotient.value = this->value / divisor.value;
	return quotient;
}


const BigInteger BigInteger::operator % (const BigInteger& divisor) const
{
	BigInteger quotient;
	quotient.value = this->value % divisor.value;
	return quotient;
}


bool BigInteger::operator < (const BigInteger& b) const
{
	return this->value < b.value;
}


bool BigInteger::operator > (const BigInteger& b) const
{
	return this->value > b.value;
}


bool BigInteger::operator <= (const BigInteger& b) const
{
	return this->value <= b.value;
}


bool BigInteger::operator >= (const BigInteger& b) const
{
	return this->value >= b.value;
}


bool BigInteger::operator == (const BigInteger& b) const
{
	return this->value == b.value;
}


bool BigInteger::operator != (const BigInteger& b) const
{
	return this->value != b.value;
}


std::string BigInteger::getAsString(void) const
{
	std::stringstream txt;
	txt << value;
	return txt.str();
}


const BigInteger BigInteger::pow(const BigInteger& base, const BigInteger& exponent)
{
	return BigInteger(
			static_cast<long long> (::pow(base.value, exponent.value))
			);
}


const BigInteger BigInteger::root(const BigInteger& a, const BigInteger& b)
{
	return BigInteger(
			static_cast<long long> (::pow(a.value, 1.0 / b.value))
			);
}


const BigInteger BigInteger::ggt(const BigInteger& _a, const BigInteger& _b)
{
	BigInteger a;
	BigInteger b;

	if (_a > _b) {
		a = _a;
		b = _b;
	}
	else {
		a = _b;
		b = _a;
	}

	while (b != 0 && a != 0) {
		BigInteger mod = a % b;
		a = b;
		b = mod;
	}
	return a;
}


void BigInteger::cancel(BigInteger& numerator, BigInteger& denominator)
{
	BigInteger a = ggt(numerator, denominator);
	if (a != 1) {
		numerator /= a;
		denominator /= a;
	}
}


BigInteger::PrimeFactor::PrimeFactor(int factor, int amount)
{
	this->factor = factor;
	this->amount = amount;
}


std::vector<BigInteger::PrimeFactor> BigInteger::getPrimeFactors(const BigInteger& number)
{
	BigInteger numberCpy = number;
	std::vector<PrimeFactor> ret;

	{
		auto int two = 0;
		while ((numberCpy % 2) == 0) {
			numberCpy /= 2;
			two++;
		}
		ret.push_back(PrimeFactor(2, two));
	}

	for (int i = 3; i < 1000 * 1000 * 1000; i += 2) {
		int num = 0;
		while ((numberCpy % i) == 0) {
			numberCpy /= i;
			num++;
		}
		ret.push_back(PrimeFactor(i, num));
	}

	return ret;
}

